#pragma once
#include <functional>
#include <cstdint>
#include <memory>
#include <vector>
#include <unordered_map>
#include <sys/timerfd.h>
#include "Channel.hpp"

using TaskFunc = std::function<void()>;
using ReleaseFunc = std::function<void()>;

class EventLoop;
class TimerTask
{
private:
    uint64_t _id;         // 任务id
    TaskFunc _task;       // 任务
    uint32_t _timeout;    // 等待超时时间
    bool _cancaled;       // 任务是否取消
    ReleaseFunc _release; // 任务执行完成后执行的动作

public:
    TimerTask(uint64_t id, const TaskFunc &task, uint32_t timeout)
        : _id(id), _task(task), _timeout(timeout), _cancaled(false)
    {
    }
    ~TimerTask()
    {
        if (_cancaled == false)
            _task();

        _release();
    }

    uint32_t DelayTime() { return _timeout; }
    void SetRelease(const ReleaseFunc &release) { _release = release; }
    void Cancal()
    {
        if (this == nullptr)
        {
            int i = 1;
        }
        _cancaled = true;
    }
};

class TimeWheel
{
private:
    using TaskWeak = std::weak_ptr<TimerTask>;
    using TaskPtr = std::shared_ptr<TimerTask>;
    int _tick;
    int _capicity;
    std::vector<std::vector<TaskPtr>> _wheel;
    std::unordered_map<uint64_t, TaskWeak> _timers;

    EventLoop *_loop;
    int _timefd;
    std::unique_ptr<Channel> _timer_channel;

    static int CreateTimerfd()
    {
        int timerfd = timerfd_create(CLOCK_MONOTONIC, 0);
        if (timerfd < 0)
        {
            std::cerr << "TIMERFD CREATE FAILED!" << std::endl;
            abort();
        }

        struct itimerspec ts;
        ts.it_value.tv_sec = 1;
        ts.it_value.tv_nsec = 0;
        ts.it_interval.tv_sec = 1;
        ts.it_interval.tv_nsec = 0;

        timerfd_settime(timerfd, 0, &ts, NULL);
        return timerfd;
    }

    void RemoveTimer(uint64_t id)
    {
        auto it = _timers.find(id);
        if (it == _timers.end())
            return;
        _timers.erase(it);
    }

    int ReadTimerfd()
    {
        uint64_t times = 0;
        int ret = ::read(_timefd, &times, 8);
        if (ret < 0)
        {
            std::cerr << "READ TIMERFD FAILED!!" << std::endl;
            abort();
        }
        return times;
    }

    // 执行任务
    void RunTimerTask()
    {
        _wheel[_tick].clear();
        _tick = (_tick + 1) % _capicity;
    }

    void OnTime()
    {
        int times = ReadTimerfd();
        for (int i = 0; i < times; ++i)
            RunTimerTask();
    }

    // 添加任务
    void TimerAddInLoop(uint64_t id, const TaskFunc &task, uint32_t delay)
    {
        TaskPtr tp(new TimerTask(id, task, delay));
        int pos = (_tick + delay) % _capicity;
        tp->SetRelease(std::bind(&TimeWheel::RemoveTimer, this, id));
        _wheel[pos].push_back(tp);
        _timers[id] = TaskWeak(tp);
    }

    // 刷新任务
    void TimerRefreshInLoop(uint64_t id)
    {
        auto it = _timers.find(id);
        if (it == _timers.end())
            return;
        TaskPtr tp = it->second.lock();
        uint32_t delay = tp->DelayTime();
        int pos = (_tick + delay) % _capicity;
        _wheel[pos].push_back(tp);
    }

    // 取消任务
    void TimerCancalInLoop(uint64_t id)
    {
        auto it = _timers.find(id);
        if (it == _timers.end())
            return;
        TaskPtr tp = it->second.lock();
        if (tp)
            tp->Cancal();
    }

public:
    TimeWheel(EventLoop *loop)
        : _tick(0), _capicity(60), _wheel(_capicity), _loop(loop), _timefd(CreateTimerfd()),
          _timer_channel(new Channel(_loop, _timefd))
    {
        _timer_channel->SetReadCallback(std::bind(&TimeWheel::OnTime, this));
        _timer_channel->EnableRead();
    }
    ~TimeWheel() {}

    // 添加任务
    void TimerAdd(uint64_t id, const TaskFunc &task, uint32_t delay);
    // 刷新任务
    void TimerRefresh(uint64_t id);
    // 取消任务
    void TimerCancal(uint64_t id);

    bool HasTimer(uint64_t id)
    {
        auto it = _timers.find(id);
        return it != _timers.end();
    }
};